package com.example.demo.controller;

import com.example.demo.crawlscript.CSDNCrawler;
import com.example.demo.es.HotWord;
import com.example.demo.es.NewsEntity;
import com.example.demo.es.SearchLogEntity;
import com.example.demo.service.NewsService;
import com.example.demo.service.SearchLogService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.analysis.util.ClasspathResourceLoader;
import org.elasticsearch.action.search.SearchAction;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.*;
import org.elasticsearch.search.aggregations.bucket.terms.*;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortMode;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchHitsIterator;
import org.springframework.data.elasticsearch.core.query.HighlightQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;

@RestController
@RequestMapping("es")
public class EsController {

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @GetMapping("create")
    public void createIndex(){
        CSDNCrawler csdnCrawler = new CSDNCrawler("test", true);
        try {
            csdnCrawler.start(4);
        } catch (Exception e) {

        }

        List<NewsEntity> newsEntities = csdnCrawler.getNewsEntities();
        elasticsearchRestTemplate.save(newsEntities);
    }

    @CrossOrigin
    @GetMapping("search")
    public ResponseEntity<?> search(@RequestParam("keyWord") String keyWord,
                                    @RequestParam("type") String type,
                                    @RequestParam(value = "page", defaultValue = "0") Integer page,
                                    @RequestParam(value = "size", defaultValue = "10") Integer size){

        SearchLogEntity searchLogEntity = new SearchLogEntity();
        searchLogEntity.setSearchText(keyWord);
        searchLogEntity.setSuggestText(keyWord);
        elasticsearchRestTemplate.save(searchLogEntity);

        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("type", type);
        MatchQueryBuilder matchQueryBuilder1 = QueryBuilders.matchQuery("content", keyWord).analyzer("ik_smart");
        MatchQueryBuilder matchQueryBuilder2 = QueryBuilders.matchQuery("title", keyWord).analyzer("ik_smart");

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(matchQueryBuilder).should(matchQueryBuilder1).should(matchQueryBuilder2);//.should(fuzzyQueryBuilder1);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();

        HighlightBuilder highlightBuilder = new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>");
        highlightBuilder.field("title").field("content");
        nativeSearchQueryBuilder.withHighlightBuilder(highlightBuilder);
        nativeSearchQueryBuilder.withPageable(PageRequest.of(page, size));
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);

        SearchHits<NewsEntity> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), NewsEntity.class);
        List<NewsEntity> newsEntities = new ArrayList<>();
        for (SearchHit s:search
             ) {
            NewsEntity newsEntity = (NewsEntity)s.getContent();
            Map<String, List<String>> highlightFields = s.getHighlightFields();
            List<String> stringList = highlightFields.get("title");
            if (stringList != null &&!stringList.isEmpty()){
                newsEntity.setTitle(stringList.get(0));
            }

            if (highlightFields.containsKey("content")){
                newsEntity.setDescription(StringUtils.join(highlightFields.get("content"), ","));
                List<String> content = highlightFields.get("content");
                for (String content2:content
                ) {
                    String oldContent = StringUtils.replace(content2, "<span style='color:red'>", "").replace("</span>", "");
                    String replace = StringUtils.replace(newsEntity.getContent(), oldContent, content2);
                    newsEntity.setContent(replace);
                }

            }

            newsEntities.add(newsEntity);
        }
        Map<String, Object> data = new HashMap<>();
        data.put("data", newsEntities);
        data.put("count", search.getTotalHits());
        return ResponseEntity.ok(data);
    }

    @CrossOrigin
    @GetMapping("hot")
    public ResponseEntity<?> hotKeyWord(){
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(matchAllQueryBuilder);

        TermsAggregationBuilder field = AggregationBuilders.terms("hotword").field("searchText")
                .size(5).order(BucketOrder.count(false));
        nativeSearchQueryBuilder.addAggregation(field);
        SearchHits<SearchLogEntity> search = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), SearchLogEntity.class);
        Aggregations aggregations = search.getAggregations();
        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();
        ParsedStringTerms playcount = (ParsedStringTerms)stringAggregationMap.get("hotword");

        Iterator<? extends Terms.Bucket> iterator = playcount.getBuckets().iterator();
        List hotwords = new ArrayList<>();
        while (iterator.hasNext()){
            Terms.Bucket next = iterator.next();
            String keyAsString = next.getKeyAsString();
            HotWord hotWord = new HotWord();
            hotWord.setValue(keyAsString);
            hotWord.setDocCount(next.getDocCount());
            hotwords.add(hotWord);
        }

        Collections.sort(hotwords);
        return ResponseEntity.ok(hotwords);
    }


    /**
     * 未搞明白
     * @param keyWord
     * @return
     */
    @GetMapping("suggest")
    public ResponseEntity<?> suggestWord(@RequestParam("keyWord") String keyWord){
        PhraseSuggestionBuilder searchText = SuggestBuilders.phraseSuggestion("searchText")
                .text(keyWord).size(5);
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("suggestDistrict", searchText);
        SearchResponse response = elasticsearchRestTemplate.suggest(suggestBuilder, SearchLogEntity.class);
        Suggest suggest = response.getSuggest();
        Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestDistrict = suggest.getSuggestion("suggestDistrict");
        Set<String> suggestSet = new HashSet<>();
        for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> g:suggestDistrict
             ) {
            if (!g.getOptions().isEmpty()){
                List<? extends Suggest.Suggestion.Entry.Option> options = g.getOptions();
                for (Suggest.Suggestion.Entry.Option option : options) {
                    String tip = option.getText().toString();
                    if (!suggestSet.contains(tip)){
                        suggestSet.add(tip);
                    }
                }
            }
        }

        return null;
    }

    @GetMapping("my_dic")
    public void myDic(HttpServletResponse response) throws Exception{
        ClassPathResource classPathResource = new ClassPathResource("statics/my_dict.dic");
        File file = classPathResource.getFile();
        outPut(file, response);
    }

    @GetMapping("stop_dic")
    public void stopDic(HttpServletResponse response) throws Exception{
        ClassPathResource classPathResource = new ClassPathResource("statics/extra_stopword.dic");
        File file = classPathResource.getFile();
        outPut(file, response);
    }


    private void outPut(File file, HttpServletResponse response) throws Exception{
        String content = "";
        if (file.exists()){
            FileInputStream fi = new FileInputStream(file);
            byte[] buffer = new byte[(int) file.length()];
            int offset = 0, numRead = 0;
            while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
                offset += numRead;
            }
            fi.close();
            content = new String(buffer, "UTF-8");
        }
        OutputStream out= response.getOutputStream();
        response.setHeader("Last-Modified", String.valueOf(content.length()));
        response.setHeader("ETag",String.valueOf(content.length()));
        response.setContentType("text/plain; charset=utf-8");
        out.write(content.getBytes("utf-8"));
        out.flush();
    }


 }
